#include "app_protect.h"

#include "app_control.h"
#include "common_debug.h"
#include "drv_adc.h"
#include "drv_gpio.h"
#include "inf_bts7020.h"
#include "inf_heating_pad.h"
#include "inf_solenoid_valve.h"

#include <string.h>

/* 电源 */
#define ADC_BAT_CH   ADC_CHANNEL_18
/* 风扇 */
#define ADC_FAN_CH   ADC_CHANNEL_9
/* 加热主驾驶 */
#define ADC_HEATL_CH ADC_CHANNEL_8

/* 泵和阀 */
#define ADC_P_V_CH   ADC_CHANNEL_15
/* 加热次驾驶 */
#define ADC_HEATR_CH ADC_CHANNEL_16

/* NTC1 */
#define ADC_NTC1_CH ADC_CHANNEL_4

/* SW1 */
#define ADC_SW1_CH ADC_CHANNEL_10

/* SW2 */
#define ADC_SW2_CH ADC_CHANNEL_0

#define BAT_AD_EN_PIN_NUM GET_PIN_NUM(E, 10)

#define ADC_VREFH               5000U
#define ADC_VREFL               0U
#define ADC_VALUE_MAX           ((1U << 12U) - 1U)
#define DIVIDER_RESISTANCE      3300.0f
#define DIVIDER_RESISTANCE_HEAT 2000.0f

#define PUMP_VALVE_IS_K          3700U
#define PUMP_MAX_ELECTRICITY_MA  1500U /* 泵最大电流 1500ma */
#define VALVE_MAX_ELECTRICITY_MA 4000U /* 阀最大电流 4000ma */

#define FAN_IS_K               3700U
#define FAN_MAX_ELECTRICITY_MA 4000U   /* 风扇最大电流 */

#define HEAT_IS_K               5400U
#define HEAT_MAX_ELECTRICITY_MA 4000U  /* 加热最大电流 */

static result_e app_protect_adc_config(void);
static void     app_protect_update_ad_val(void);
static void     app_protect_update_cal_val(void);
static void     app_protect_data_filter(void);
static void     app_protect_bat_abnormal_handle(void);
static void     app_protect_pump_valve_abnormal_handle(void);
static void     app_protect_fan_abnormal_handle(void);
static void     app_protect_heat_abnormal_handle(void);

#if ADC_FILTER_SWITCH
static int32_t app_protect_update_filter(mov_avg_filter_t *filter, int32_t sample_val);
#endif

/* 保护模块监控数据 */
static monitor_t monitor_data = { 0 };

/* 保护模块ADC采样数据缓冲区 */
int32_t adc_real_data_list[ADC_IN_IDX_MAX] = { 0 };

/**
 * @brief 初始化保护模块
 *
 * @return result_e 初始化结果, 成功返回RESULT_STATUS_OK, 失败返回其他错误码
 */
result_e app_protect_init(void)
{
    result_e result = app_protect_adc_config();
    if (result != RESULT_STATUS_OK) {
        return result;
    }

    return RESULT_STATUS_OK;
}

/**
 * @brief 保护模块处理函数
 *
 */
void app_protect_handle(void)
{
    app_protect_update_ad_val();
    app_protect_update_cal_val();
#if ADC_FILTER_SWITCH
    app_protect_data_filter();
#endif

    /* BAT异常处理 */
    app_protect_bat_abnormal_handle();

    /* PUMP VALVE异常处理 */
    app_protect_pump_valve_abnormal_handle();

    /* 风扇异常处理 */
    app_protect_fan_abnormal_handle();

    /* 加热异常处理 */
    app_protect_heat_abnormal_handle();
}

/**
 * @brief 加热异常处理函数
 *
 */
static void app_protect_heat_abnormal_handle(void)
{
    // LOG("HEAT L: %d, HEAT R: %d\n", monitor_data.heatl_cal_val, monitor_data.heatr_cal_val);

    if (monitor_data.heatl_cal_val > HEAT_MAX_ELECTRICITY_MA) {
        /* 关闭加热左 */
        inf_heat_set_gear(HEAT_IDX_HEATL, HEAT_GEAR_CLOSE);
    }

    if (monitor_data.heatr_cal_val > HEAT_MAX_ELECTRICITY_MA) {
        /* 关闭加热右 */
        // TODO
    }
}

/**
 * @brief 风扇异常处理函数
 *
 */
static void app_protect_fan_abnormal_handle(void)
{
    // LOG("FAN L: %d, FAN R: %d\n", monitor_data.fanl_cal_val, monitor_data.fanr_cal_val);

    if (monitor_data.fanl_cal_val > FAN_MAX_ELECTRICITY_MA) {
        /* 关闭风扇左 */
        app_control_switch(BTS7020_DEVICE_FAN, SWITCH_TYPE_FANL, false);
    }

    if (monitor_data.fanr_cal_val > FAN_MAX_ELECTRICITY_MA) {
        /* 关闭风扇右 */
        app_control_switch(BTS7020_DEVICE_FAN, SWITCH_TYPE_FANR, false);
    }
}

/**
 * @brief 泵阀高策开关处理异常函数
 *
 */
static void app_protect_pump_valve_abnormal_handle(void)
{
    // LOG("PUMP a: %d\n", monitor_data.pump_cal_val);
    // LOG("VALVE a: %d\n", monitor_data.valve_cal_val);

    if (monitor_data.pump_cal_val > PUMP_MAX_ELECTRICITY_MA) {
        /* 关闭泵高策开关 */
        app_control_switch(BTS7020_DEVICE_PUMP_VALVE, SWITCH_TYPE_PUMP, false);
    }

    if (monitor_data.valve_cal_val > VALVE_MAX_ELECTRICITY_MA) {
        /* 关闭阀高策开关 */
        app_control_switch(BTS7020_DEVICE_PUMP_VALVE, SWITCH_TYPE_VALVE, false);
    }
}

/**
 * @brief BAT异常处理函数
 *
 */
static void app_protect_bat_abnormal_handle(void)
{
    static uint8_t update_counter = 0;

    /* 每10次更新一次电压补偿系数 */
    if (++update_counter > 10) {
        update_counter = 0;

        /* 计算实际电压 */
        int32_t real_voltage    = monitor_data.bat_cal_val * 10;
        /* 四舍五入到伏级别，更防止电压跳变 */
        int32_t rounded_voltage = (real_voltage + 500) / 1000 * 1000;

        if (rounded_voltage > 0) {
            voltage_comp_factor = (float)SOLENOID_VALVE_BASE_VOLTAGE / rounded_voltage;
        }
        else {
            voltage_comp_factor = 0.0;
        }

        // LOG("voltage_comp_factor: %d\n", (int)(voltage_comp_factor * 100));
    }
}

/**
 * @brief 数据滤波函数，防止数据因为干扰导致大幅度跳变
 *
 */
static void app_protect_data_filter(void)
{
    /* BAT移动平均滤波 */
    monitor_data.bat_cal_val =
        app_protect_update_filter(&monitor_data.bat_filter, monitor_data.bat_cal_val);

    /* 泵阀电流移动平均滤波 */
    monitor_data.pump_cal_val =
        app_protect_update_filter(&monitor_data.pump_filter, monitor_data.pump_cal_val);
    /* 阀电流移动平均滤波 */
    monitor_data.valve_cal_val =
        app_protect_update_filter(&monitor_data.valve_filter, monitor_data.valve_cal_val);

    /* 风扇左电流移动平均滤波 */
    monitor_data.fanl_cal_val =
        app_protect_update_filter(&monitor_data.fanl_filter, monitor_data.fanl_cal_val);
    /* 风扇右电流移动平均滤波 */
    monitor_data.fanr_cal_val =
        app_protect_update_filter(&monitor_data.fanr_filter, monitor_data.fanr_cal_val);

    /* 加热左电流移动平均滤波 */
    monitor_data.heatl_cal_val =
        app_protect_update_filter(&monitor_data.heatl_filter, monitor_data.heatl_cal_val);
    /* 加热右电流移动平均滤波 */
    monitor_data.heatr_cal_val =
        app_protect_update_filter(&monitor_data.heatr_filter, monitor_data.heatr_cal_val);
}

#if ADC_FILTER_SWITCH
/**
 * @brief 更新移动平均滤波器
 *
 * @param filter        移动平均滤波器指针
 * @param sample_val    新样本值
 * @return int32_t      滤波后的值
 */
static int32_t app_protect_update_filter(mov_avg_filter_t *filter, int32_t sample_val)
{
    /* 如果缓冲区已满，减去将被替换的值 */
    if (filter->count == ADC_FILTER_WINDOW_SIZE) {
        filter->sum -= filter->buf[filter->index];
    }
    else {
        ++filter->count;
    }

    /* 添加新值到缓冲区 */
    filter->buf[filter->index] = sample_val;
    filter->sum += sample_val;

    /* 更新索引 */
    filter->index = (filter->index + 1) % ADC_FILTER_WINDOW_SIZE;

    /* 返回平均值 */
    return filter->sum / filter->count;
}
#endif

/**
 * @brief 计算保护模块监控数据
 *
 */
static void app_protect_update_cal_val(void)
{
    /* BAT模块电压值 */
    monitor_data.bat_cal_val = (monitor_data.bat_ad_real_val * (ADC_VREFH - ADC_VREFL)) / ADC_VALUE_MAX;

    /* 泵阀电流值 */
    monitor_data.pump_cal_val =
        ((monitor_data.pump_ad_real_val * (ADC_VREFH - ADC_VREFL)) / ADC_VALUE_MAX) / DIVIDER_RESISTANCE *
        PUMP_VALVE_IS_K;
    monitor_data.valve_cal_val =
        ((monitor_data.valve_ad_real_val * (ADC_VREFH - ADC_VREFL)) / ADC_VALUE_MAX) / DIVIDER_RESISTANCE *
        PUMP_VALVE_IS_K;

    /* 风扇电流值 */
    monitor_data.fanl_cal_val =
        ((monitor_data.fanl_ad_real_val * (ADC_VREFH - ADC_VREFL)) / ADC_VALUE_MAX) / DIVIDER_RESISTANCE *
        FAN_IS_K;
    monitor_data.fanr_cal_val =
        ((monitor_data.fanr_ad_real_val * (ADC_VREFH - ADC_VREFL)) / ADC_VALUE_MAX) / DIVIDER_RESISTANCE *
        FAN_IS_K;

    /* 加热模块电流值 */
    monitor_data.heatl_cal_val =
        ((monitor_data.heatl_ad_real_val * (ADC_VREFH - ADC_VREFL)) / ADC_VALUE_MAX) /
        DIVIDER_RESISTANCE_HEAT * HEAT_IS_K;
    monitor_data.heatr_cal_val =
        ((monitor_data.heatr_ad_real_val * (ADC_VREFH - ADC_VREFL)) / ADC_VALUE_MAX) /
        DIVIDER_RESISTANCE_HEAT * HEAT_IS_K;
}

/**
 * @brief 更新ADC的值
 *
 */
static void app_protect_update_ad_val(void)
{
    bts7020_list[BTS7020_DEVICE_PUMP_VALVE].ad_val_buf[bts7020_list[BTS7020_DEVICE_PUMP_VALVE].dsel] =
        adc_real_data_list[ADC_IN_IDX_P_V];
    bts7020_list[BTS7020_DEVICE_FAN].ad_val_buf[bts7020_list[BTS7020_DEVICE_FAN].dsel] =
        adc_real_data_list[ADC_IN_IDX_FAN];

    /* adc实际值更新到监控器中 */
    monitor_data.bat_ad_real_val   = adc_real_data_list[ADC_IN_IDX_BAT];
    monitor_data.fanl_ad_real_val  = bts7020_list[BTS7020_DEVICE_FAN].ad_val_buf[BTS7020_IN0];
    monitor_data.fanr_ad_real_val  = bts7020_list[BTS7020_DEVICE_FAN].ad_val_buf[BTS7020_IN1];
    monitor_data.heatl_ad_real_val = adc_real_data_list[ADC_IN_IDX_HEATL];
    monitor_data.heatr_ad_real_val = adc_real_data_list[ADC_IN_IDX_HEATR];
    monitor_data.pump_ad_real_val  = bts7020_list[BTS7020_DEVICE_PUMP_VALVE].ad_val_buf[BTS7020_IN0];
    monitor_data.valve_ad_real_val = bts7020_list[BTS7020_DEVICE_PUMP_VALVE].ad_val_buf[BTS7020_IN1];
}

/**
 * @brief 配置ADC, 用于获取电压值
 *
 * @return result_e 配置结果, 成功返回RESULT_STATUS_OK, 失败返回其他错误码
 */
static result_e app_protect_adc_config(void)
{
    snf_gpio_config_t gpio_config = {
        .pin_num    = BAT_AD_EN_PIN_NUM,
        .mode       = DRV_GPIO_PIN_MODE_OUTPUT,
        .init_level = DRV_GPIO_PIN_LEVEL_HIGH,
    };
    CHECK_RESULT(snf_drv_gpio_init(&gpio_config), "BAT ad en pin init fail\n");

    snf_adc_config_t adc0_config = {
        .instance       = ADC_INSTANCE_ADC0,
        .channel_list   = { ADC_BAT_CH, ADC_FAN_CH, ADC_HEATL_CH, ADC_NTC1_CH, ADC_SW2_CH },
        .channel_size   = ADC_IN_IDX_ADC0_MAX,
        .mode           = ADC_MODE_CONTINUE,
        .dma_channel    = ADC_DMA_CHANNEL_4,
        .adc_sample_buf = adc_real_data_list,
        .callback       = NULL,
        .param          = NULL,
    };
    CHECK_RESULT(snf_drv_adc_init(&adc0_config), "ADC0 init fail\n");

    snf_adc_config_t adc1_config = {
        .instance       = ADC_INSTANCE_ADC1,
        .channel_list   = { ADC_P_V_CH, ADC_HEATR_CH, ADC_SW1_CH },
        .channel_size   = ADC_IN_IDX_ADC1_MAX,
        .mode           = ADC_MODE_CONTINUE,
        .dma_channel    = ADC_DMA_CHANNEL_5,
        .adc_sample_buf = &adc_real_data_list[ADC_IN_IDX_P_V],
        .callback       = NULL,
        .param          = NULL,
    };
    CHECK_RESULT(snf_drv_adc_init(&adc1_config), "ADC1 init fail\n");

    return RESULT_STATUS_OK;
}
